<?php
/**
 * Created by PhpStorm.
 * User: caoyong
 * Date: 15/3/20
 * Time: 08:51
 */
namespace Caoyong\Tests;

use \PHPUnit_Framework_TestCase;
use Caoyong\Tests\Objects\Person;
use Caoyong\PHPCore\Object;
use Caoyong\PHPCore\Collection;

class CoreTest extends PHPUnit_Framework_TestCase
{
    public function testObject()
    {
        $person = new Person();
        $classname = $person->className();

        $this->assertInstanceOf(Object::className(), $person, $classname
            . ' must be instance of ' . Object::className() . '.');
        $this->assertTrue($person->hasProperty('name'), 'Unknown property: name');
        $this->assertFalse(isset($person->name), 'property: name is not null');
        $this->assertFalse($person->hasProperty('age'), 'Unknown property: age');
        $this->assertFalse(isset($person->age), 'Unknown property: age');

        $person->name = 'test';
        $this->assertEquals('test', $person->name, 'Property: name is not "test"');
        unset($person->name);
        $this->assertNull($person->name, 'Property: name is "' . $person->name . '"');
        $this->assertTrue($person->hasMethod('test'), 'Call undefined method: ' . $classname . '::test');
    }

    /**
     *
     */
    public function testCollection()
    {
        $array = [
            ['id' => 1,'name' => 'jack'],
            ['id' => 1,'name' => 'jim'],
        ];
        $classname = Collection::class;
        $collection = new Collection($array);

        //接口测试
        $this->assertInstanceOf('Caoyong\PHPCore\Interfaces\ArrayableInterface', $collection, $classname.
            ' mush be instance of Caoyong\PHPCore\Interfaces\ArraybleInterface');
        $this->assertInstanceOf('Caoyong\PHPCore\Interfaces\JsonableInterface', $collection, $classname .
            ' mush be instance of Caoyong\PHPCore\Interfaces\JsonableInterface');

        //toJson测试
        $result = json_encode($array) === $collection->toJson();
        $this->assertTrue($result, 'Collection json string must be equals $array json string');

        $this->assertInstanceOf('\ArrayAccess', $collection, $classname . ' mush be instance of ArrayAccess');
        $this->assertInstanceOf('\JsonSerializable', $collection, $classname . ' mush be instance of JsonSerializable');
        $this->assertInstanceOf('\Countable', $collection, $classname . ' mush be instance of Countable');

        $this->assertEquals($array, $collection->all(), 'The method: all return value is not equal to variable $array');

        //增加元素has
        $collection->set('has', 1);
        $this->assertTrue($collection->has('has'), 'Object has key: has,but the method return false');
        $this->assertFalse($collection->has('nothas'), 'Object not has key: nothas,but the method return true');
        $this->assertEquals(1, $collection->get('has'), 'Key: has`s value is 1');
        $this->assertEquals(2, $collection->get('nothas', function () {
            return 2;
        }), 'Key: nothas`s value is 2');
        $this->assertEquals(3, $collection->get('nothas', 3), 'Key: nothas`s value is 3');

        //尾部增加值：1
        $collection->push(1);
        $this->assertTrue($collection->hasValue('1'), 'Collection has value 1 in the weak type');
        $this->assertFalse($collection->hasValue('1', true), 'Collection does not have 1 in the strongly type');
        $this->assertEquals(1, $collection->end(), 'Collection` last element`s value is 1');

        //获取当前长度
        $count = $collection->count();
        $this->assertGreaterThan(0, $count, 'Total number of Collection`s elements greater than 0');

        //第一个元素出栈
        $shift = $collection->shift();
        $this->assertTrue($shift === $array[0], 'The shift element must equals $array[0]');
        $this->assertEquals($count-1, $collection->count(), 'Total number of Collection`s elements less than $count 1');

        //出栈元素放回第一个位置
        $collection->unshift($shift);
        $this->assertTrue($shift === $array[0], 'The shift item must be equals $array[0]');
        $this->assertCount($count, $collection, 'Total number of Collection`s elements less than $count 1');

        //尾部元素出栈，这里应该得到之前push进去的1
        $pop = $collection->pop();
        $this->assertEquals(1, $pop, 'The pop item must be equals 1');
        $this->assertCount($count-1, $collection, 'Total number of Collection`s elements less than $count 1');
        $this->assertTrue($collection->keyExists('has'), 'Key: has exists');
        $this->assertEquals([0,1,'has'], $collection->keys(), 'Collection should be [0,1,\'has\']');

        //删除元素has
        $collection->remove('has');
        $this->assertFalse($collection->keyExists('has'), 'Key: has does not exists');
        $this->assertEquals([0,1], $collection->keys(), 'Collection should be [0,1]');

        //返回模式
        $map_array = $collection->map(function ($value) {
            array_push($value, 'map value');
            return $value;
        });
        foreach ($map_array as $item) {
            $this->assertEquals('map value', end($item), 'End of Items should be "map value"');
        }

        //合并模式
        $collection->map(function ($value) {
            array_push($value, 'map value');
            return $value;
        }, true);
        $collection->map(function ($value) {
            $this->assertEquals('map value', end($value), 'End of Items should be "map value"');
        });

        //重置元素为初始值
        $collection->resetOriginal();
        $this->assertTrue($array === $collection->all(), 'After reset,Collection must be $array');

        //合并
        $merge[0] = [
            'id' => 3,
            'name' => 'smith'
        ];
        $new = $collection->merge($merge);
        $result = $merge[0] === $new->end();
        $this->assertTrue($result, 'After merge,the end of items should be [\'id\' => 3,\'name\' => \'smith\']');

        $merge[1] = [
            'id' => 4,
            'name' => 'john'
        ];

        $new = $collection->merge($merge);
        $result = $merge[0] === $new->get(2);
        $this->assertTrue($result, 'After merge,the 2nd of items should be [\'id\' => 3,\'name\' => \'smith\']');
        $result = $merge[1] === $new->get(3);
        $this->assertTrue($result, 'After merge,the 3rd of items should be [\'id\' => 4,\'name\' => \'join\']');

        //unique测试
        $new = new Collection([1,2,2,3]);
        //返回模式
        $unique = $new->unique();
        $this->assertCount(3, $unique, 'After unique,total of items should be 3');
        //合并模式
        $new->unique(true);
        $this->assertCount(3, $unique, 'After unique,total of items should be 3');

        //values测试
        $this->assertEquals($array, $collection->values(), 'Collection values mush be $array ');

        //first,ksort,shuffle测试
        $items = ['b' => 1,'a' => 2,'c' => 5,'f' => 6,'z' => 9,'h' => 100];
        $new = new Collection($items);
        $this->assertEquals(1, $new->first(), 'The 1st item must be 1');
        $new->ksort();
        $this->assertEquals(2, $new->first(), 'The 1st item mush be 2');
        $new->shuffle();
        $this->assertTrue($new->all() !== $items);

        $new = new Collection([1,2,new Collection([3,4])]);
        $this->assertTrue([1,2,[3,4]] === $new->toArray(), 'ToArray Error');
    }
}
